package com.example.a_middlewares.ElasticSearch;

import com.alibaba.fastjson.JSON;
import org.apache.http.HttpHost;
import org.elasticsearch.action.admin.indices.alias.Alias;
import org.elasticsearch.action.admin.indices.create.CreateIndexRequest;
import org.elasticsearch.action.admin.indices.create.CreateIndexResponse;
import org.elasticsearch.action.bulk.BulkRequest;
import org.elasticsearch.action.bulk.BulkResponse;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.index.IndexResponse;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestClient;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentFactory;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.index.query.*;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.aggregations.Aggregation;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.aggregations.Aggregations;
import org.elasticsearch.search.aggregations.bucket.terms.ParsedLongTerms;
import org.elasticsearch.search.aggregations.bucket.terms.Terms;
import org.elasticsearch.search.aggregations.bucket.terms.TermsAggregationBuilder;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightField;
import org.elasticsearch.search.sort.SortBuilders;
import org.elasticsearch.search.sort.SortOrder;

import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * ElasticSearch example
 */
public class app {
    private static RestHighLevelClient client;

    static {
        client = new RestHighLevelClient(
                RestClient.builder(new HttpHost("192.168.118.131", 9200, "http")));
    }
    public static void closeClient() throws IOException {
        if (null == client) {
            client.close();
        }
    }

    public static void main(String[] args) throws IOException {
        // 0 创建
        // createIndex();

        // 新增记录
        // putData();
        // putBatchData();

        // 检索记录
        // queryOne("id", "2");
        // queryAll();
        // rangeQuery();
        // fuzzyQuery(); // 模糊查询
        // wildCardQuery(); // 通配符
        // pageQuery(); // 分页查询
        // highLightQuery(); // 高亮查询
        // boolQuery();
        // aggregateQuery();

        // 关闭
        closeClient();
    }

    /**
     * 创建索引
     */
    public static void createIndex() throws IOException {
        // 路径：<index>/<type>/[<id>]     people/_doc/12
        CreateIndexRequest createIndexRequest = new CreateIndexRequest("people");
        createIndexRequest.timeout(new TimeValue(6, TimeUnit.SECONDS));
        //setting配置
        createIndexRequest.settings(Settings.builder()
                .put("index.number_of_shards", 1)
                .put("index.number_of_replicas", 1));
        //mapping配置
        XContentBuilder mapping = XContentFactory.jsonBuilder()
                .startObject()
                .startObject("properties")
                .startObject("id").field("type", "integer").endObject()
                .startObject("name").field("type", "text").endObject()//.field("analyzer", "ik_max_word").endObject()
                .startObject("age").field("type", "integer").endObject()
                .startObject("sex").field("type", "text").endObject()
                .startObject("address").field("type", "text").endObject()//.field("analyzer", "ik_max_word").endObject()
                .startObject("phone").field("type", "text").endObject()
                .startObject("email").field("type", "text").endObject()
                .startObject("say").field("type", "text").endObject()//.field("analyzer", "ik_max_word").endObject()
                .endObject()
                .endObject();
        //设置mapping和setting
        createIndexRequest.mapping("_doc", mapping);
        //设置别名
        createIndexRequest.alias(new Alias("people_alias"));
        //创建索引同步执行
        CreateIndexResponse createIndexResponse = client.indices().create(createIndexRequest, RequestOptions.DEFAULT);

        boolean acknowledged = createIndexResponse.isAcknowledged();//指示是否所有节点都已确定请求
        boolean shardsAcknowledged = createIndexResponse.isShardsAcknowledged();//指示是否超时之前为索引中的每个分片启动了必需的分片副本数
        System.out.println("是否所有节点都已经确认:" + acknowledged);
        System.out.println("是否每个分片启动必须都已经确认:" + shardsAcknowledged);
    }

    /**
     * 添加单个数据
     *  查看该数据 http://192.168.118.131:9200/people/_doc/1
     */
    public static void putData() throws IOException {
        Person person = new Person(1, "美男name", 26, 1, "水泊梁山",
                "13811115555", "xx@xx.com", "hello world!!!");
        IndexRequest indexRequest = new IndexRequest("people", "_doc", "1")
                .source(JSON.toJSONString(person), XContentType.JSON);
        IndexResponse res = client.index(indexRequest, RequestOptions.DEFAULT);
        System.out.println(res.toString());
    }

    /**
     * 批量添加数据
     */
    public static void putBatchData() throws IOException {
        //创建批量插入请求
        BulkRequest bulkRequest = new BulkRequest();
        //生成插入数据
        // Person lujunyi = new Person(1, "玉麒麟卢俊义", 28, 1, "水泊梁山", "17666666666", "lujunyi@itcast.com", "hello world今天天气还不错");
        Person wuyong = new Person(2, "智多星吴用", 45, 1, "水泊梁山", "17666666666", "wuyong@itcast.com", "行走四方，抱打不平");
        Person gongsunsheng = new Person(3, "入云龙公孙胜", 30, 1, "水泊梁山", "17666666666", "gongsunsheng@itcast.com", "走一个");
        Person guansheng = new Person(4, "大刀关胜", 42, 1, "水泊梁山", "17666666666", "wusong@itcast.com", "我的大刀已经饥渴难耐");
        Person linchong = new Person(5, "豹子头林冲", 18, 1, "水泊梁山", "17666666666", "linchong@itcast.com", "梁山好汉");
        Person qinming = new Person(6, "霹雳火秦明", 28, 1, "水泊梁山", "17666666666", "qinming@itcast.com", "不太了解");
        Person huyanzhuo = new Person(7, "双鞭呼延灼", 25, 1, "水泊梁山", "17666666666", "huyanzhuo@itcast.com", "不是很熟悉");
        Person huarong = new Person(8, "小李广花荣", 50, 1, "水泊梁山", "17666666666", "huarong@itcast.com", "打酱油的");
        Person chaijin = new Person(9, "小旋风柴进", 32, 1, "水泊梁山", "17666666666", "chaijin@itcast.com", "吓唬人的");
        Person zhisheng = new Person(10, "花和尚鲁智深", 15, 1, "水泊梁山", "17666666666", "luzhisheng@itcast.com", "倒拔杨垂柳");
        Person wusong = new Person(11, "行者武松", 28, 1, "水泊梁山", "17666666666", "wusong@itcast.com", "二营长。。。。。。");
        // bulkRequest.add(new IndexRequest("people", "_doc", "1").source(JSON.toJSONString(lujunyi), XContentType.JSON));
        bulkRequest.add(new IndexRequest("people", "_doc", "2").source(JSON.toJSONString(wuyong), XContentType.JSON));
        bulkRequest.add(new IndexRequest("people", "_doc", "3").source(JSON.toJSONString(gongsunsheng), XContentType.JSON));
        bulkRequest.add(new IndexRequest("people", "_doc", "4").source(JSON.toJSONString(guansheng), XContentType.JSON));
        bulkRequest.add(new IndexRequest("people", "_doc", "5").source(JSON.toJSONString(linchong), XContentType.JSON));
        bulkRequest.add(new IndexRequest("people", "_doc", "6").source(JSON.toJSONString(qinming), XContentType.JSON));
        bulkRequest.add(new IndexRequest("people", "_doc", "7").source(JSON.toJSONString(huyanzhuo), XContentType.JSON));
        bulkRequest.add(new IndexRequest("people", "_doc", "8").source(JSON.toJSONString(huarong), XContentType.JSON));
        bulkRequest.add(new IndexRequest("people", "_doc", "9").source(JSON.toJSONString(chaijin), XContentType.JSON));
        bulkRequest.add(new IndexRequest("people", "_doc", "10").source(JSON.toJSONString(zhisheng), XContentType.JSON));
        bulkRequest.add(new IndexRequest("people", "_doc", "11").source(JSON.toJSONString(wusong), XContentType.JSON));
        BulkResponse res = client.bulk(bulkRequest, RequestOptions.DEFAULT);
        System.out.println(res.toString());
    }

    /**
     * 查询一条数据
     */
    public static void queryOne(String fieldName, String fieldValue) throws IOException {
        SearchRequest searchRequest = new SearchRequest("people");
        //构建条件构造器
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        //构建查询条件
        TermQueryBuilder queryBuilder = QueryBuilders.termQuery(fieldName, fieldValue);
        //将查询条件放入构造器中
        searchSourceBuilder.query(queryBuilder);
        //将查询请求中添加查询构造器
        searchRequest.source(searchSourceBuilder);

        SearchResponse searchResponse = client.search(searchRequest, RequestOptions.DEFAULT);
        SearchHit[] hits = searchResponse.getHits().getHits();
        for (SearchHit hit : hits) {
            System.out.println(hit.getSourceAsString());
        }
    }

    /**
     * 查询所有数据
     */
    public static void queryAll() throws IOException {
        SearchRequest searchRequest = new SearchRequest("people");
        //构建条件构造器
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        //构建查询条件
        MatchAllQueryBuilder matchAllQueryBuilder = QueryBuilders.matchAllQuery();
        //将查询条件放入构造器中
        searchSourceBuilder.query(matchAllQueryBuilder);
        //将查询请求中添加查询构造器
        searchRequest.source(searchSourceBuilder);
        SearchResponse searchResponse = client.search(searchRequest, RequestOptions.DEFAULT);
        SearchHit[] hits = searchResponse.getHits().getHits();
        for (SearchHit hit : hits) {
            System.out.println(hit.getSourceAsString());
        }
    }

    /**
     * 年龄范围查询
     * 查询年龄是18到28的数据
     */
    public static void rangeQuery() throws IOException {
        SearchRequest searchRequest = new SearchRequest("people");
        //构建条件构造器
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        //创建查询条件
        RangeQueryBuilder ageRangeQuery = QueryBuilders.rangeQuery("age").gt(18).lte(28);
        searchSourceBuilder.query(ageRangeQuery);
        searchRequest.source(searchSourceBuilder);
        SearchResponse searchResponse = client.search(searchRequest, RequestOptions.DEFAULT);
        SearchHit[] hits = searchResponse.getHits().getHits();
        for (SearchHit hit : hits) {
            System.out.println(hit.getSourceAsString());
        }
    }

    /**
     * 模糊查询
     */
    public static void fuzzyQuery() throws IOException {
        SearchRequest searchRequest = new SearchRequest("people");
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        FuzzyQueryBuilder fuzzyQueryBuilder = QueryBuilders.fuzzyQuery("say", "不");// HellO  .fuzziness(Fuzziness.TWO);
        searchSourceBuilder.query(fuzzyQueryBuilder);
        searchRequest.source(searchSourceBuilder);

        SearchResponse searchResponse = client.search(searchRequest, RequestOptions.DEFAULT);
        SearchHit[] hits = searchResponse.getHits().getHits();
        for (SearchHit hit : hits) {
            System.out.println(hit.getSourceAsString());
        }
    }

    /**
     * 通配符查询
     */
    public static void wildCardQuery() throws IOException {
        SearchRequest searchRequest = new SearchRequest("people");
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        WildcardQueryBuilder wildcardQueryBuilder = QueryBuilders.wildcardQuery("say", "hel*");
        searchSourceBuilder.query(wildcardQueryBuilder);
        searchRequest.source(searchSourceBuilder);

        SearchResponse searchResponse = client.search(searchRequest, RequestOptions.DEFAULT);
        SearchHit[] hits = searchResponse.getHits().getHits();
        for (SearchHit hit : hits) {
            System.out.println(hit.getSourceAsString());
        }
    }

    /**
     * 分页查询 page从0开始
     */
    public static void pageQuery() throws IOException {
        SearchRequest searchRequest = new SearchRequest("people");
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        searchSourceBuilder.from(0).size(2);
        searchRequest.source(searchSourceBuilder);

        SearchResponse searchResponse = client.search(searchRequest, RequestOptions.DEFAULT);
        SearchHit[] hits = searchResponse.getHits().getHits();
        for (SearchHit hit : hits) {
            System.out.println(hit.getSourceAsString());
        }
    }

    /**
     * 高亮查询
     */
    public static void highLightQuery() throws IOException {
        SearchRequest searchRequest = new SearchRequest("people");
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        TermQueryBuilder termQueryBuilder = QueryBuilders.termQuery("say", "不"); // hello
        HighlightBuilder say = new HighlightBuilder().field("say").preTags("<font style='color:red'>").postTags("</font>");
        searchSourceBuilder
                .query(termQueryBuilder)
                .highlighter(say)
                .from(0)
                .size(20);
        searchRequest.source(searchSourceBuilder);

        SearchResponse searchResponse = client.search(searchRequest, RequestOptions.DEFAULT);
        SearchHit[] hits = searchResponse.getHits().getHits();
        List<Person> list = new ArrayList<>();
        for (SearchHit hit : hits) {
            Person person = new Person();
            Map<String, Object> hitSourceAsMap = hit.getSourceAsMap();
            person.setId(Integer.valueOf(hitSourceAsMap.get("id").toString()));
            person.setPhone(hitSourceAsMap.get("phone").toString());
            person.setEmail(hitSourceAsMap.get("email").toString());
            person.setAge(Integer.valueOf(hitSourceAsMap.get("age").toString()));
            person.setAddress(hitSourceAsMap.get("address").toString());
            person.setName(hitSourceAsMap.get("name").toString());
            person.setSex(Integer.valueOf(hitSourceAsMap.get("sex").toString()));
            person.setSay(hitSourceAsMap.get("say").toString());
            Map<String, HighlightField> highlightFields = hit.getHighlightFields();
            if (highlightFields.containsKey("say")) {
                person.setSay(highlightFields.get("say").getFragments()[0].toString());
            }
            list.add(person);
            // System.out.println(hit.getSourceAsString()); // 这样写只有净的记录，无附增的tag
        }
        System.out.println(JSON.toJSONString(list));
    }

    /**
     * 多条件查询
     *  这个的 age 范围好像不起作用
     */
    public static void boolQuery() throws IOException {
        SearchRequest searchRequest = new SearchRequest("people");
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        RangeQueryBuilder ageRangeQuery = QueryBuilders.rangeQuery("age").gt(18).lt(28);//.lte(28);
        TermQueryBuilder sexTermQuery = QueryBuilders.termQuery("sex", "1");
        RangeQueryBuilder idRangeQuery = QueryBuilders.rangeQuery("id").from(8).to(13);
        BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();
        // multi condition
        boolQuery.should(QueryBuilders.boolQuery().must(ageRangeQuery).must(sexTermQuery)).must(idRangeQuery);

        searchSourceBuilder.query(boolQuery).sort(SortBuilders.fieldSort("age").order(SortOrder.DESC));
        searchRequest.source(searchSourceBuilder);

        SearchResponse searchResponse = client.search(searchRequest, RequestOptions.DEFAULT);
        SearchHit[] hits = searchResponse.getHits().getHits();
        for (SearchHit hit : hits) {
            System.out.println(hit.getSourceAsString());
        }
    }

    /**
     * 聚合查询（安装年龄分组）
     */
    public static void aggregateQuery() throws IOException {
        SearchRequest searchRequest = new SearchRequest("people");
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        TermsAggregationBuilder ageAggBuilder = AggregationBuilders.terms("ageAgg").field("age");
        searchSourceBuilder.aggregation(ageAggBuilder);
        searchSourceBuilder.timeout(new TimeValue(60, TimeUnit.SECONDS));
        searchRequest.source(searchSourceBuilder);
        //获取聚合的结果
        SearchResponse searchResponse = client.search(searchRequest, RequestOptions.DEFAULT);
        Aggregations aggregations = searchResponse.getAggregations();
        Map<String, Aggregation> aggregationMap = aggregations.getAsMap();
        ParsedLongTerms ageAgg = (ParsedLongTerms) aggregationMap.get("ageAgg");
        List<? extends Terms.Bucket> buckets = ageAgg.getBuckets();
        Map<String, Long> map = new HashMap<>();
        for (Terms.Bucket bucket : buckets) {
            long docCount = bucket.getDocCount();
            String keyAsString = bucket.getKeyAsString();
            System.out.println(keyAsString + "岁的有:" + docCount);
            map.put(keyAsString, docCount);
        }
        for (Map.Entry<String, Long> stringLongEntry : map.entrySet()) {
            System.out.println("key:" + stringLongEntry.getKey() + ",value:" + stringLongEntry.getValue());
        }
    }
}
